home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 September / PCWorld_2007-09_cd.bin / system / ntfs / ntfsundelete.exe / {app} / pyue / ue_runtime.pyc (.txt) < prev   
Encoding:
Python Compiled Bytecode  |  2007-07-23  |  32.4 KB  |  1,096 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. import sys
  5. import traceback
  6. import thread
  7. import os
  8. import os.path as os
  9. import app
  10. import time
  11. import locale
  12. from fstools import *
  13. from ntfs import *
  14. from ue_con import *
  15. print 'Application initialized.'
  16.  
  17. def p_unicode(s):
  18.     return unicode(s, locale.getpreferredencoding())
  19.  
  20.  
  21. class CScanMgr:
  22.     
  23.     def __init__(self):
  24.         self._CScanMgr__active_scanners = { }
  25.         self._CScanMgr__mgr_lock = threading.Lock()
  26.  
  27.     
  28.     def add_scanner(self, scanner):
  29.         self._CScanMgr__mgr_lock.acquire()
  30.         self._CScanMgr__active_scanners[scanner] = scanner
  31.         self._CScanMgr__mgr_lock.release()
  32.  
  33.     
  34.     def finish_scanner(self, scanner):
  35.         self._CScanMgr__mgr_lock.acquire()
  36.         if self._CScanMgr__active_scanners.has_key(scanner):
  37.             del self._CScanMgr__active_scanners[scanner]
  38.         
  39.         self._CScanMgr__mgr_lock.release()
  40.  
  41.     
  42.     def _lock_all(self):
  43.         for scanner in self._CScanMgr__active_scanners.values():
  44.             scanner.lock()
  45.         
  46.  
  47.     
  48.     def _unlock_all(self):
  49.         for scanner in self._CScanMgr__active_scanners.values():
  50.             scanner.unlock()
  51.         
  52.  
  53.     
  54.     def interlocked_call(self, callable, *args, **kwargs):
  55.         '''
  56.             Blocks all scanners, execute callable
  57.             and unlocks scanners
  58.         '''
  59.         self._CScanMgr__mgr_lock.acquire()
  60.         self._lock_all()
  61.         
  62.         try:
  63.             callable(*args, **kwargs)
  64.         finally:
  65.             self._unlock_all()
  66.             self._CScanMgr__mgr_lock.release()
  67.  
  68.  
  69.     
  70.     def find_scanner_for_drive(self, drive_name):
  71.         '''
  72.             search scanner for drive, pause it,
  73.             and return result
  74.         '''
  75.         result = None
  76.         self._CScanMgr__mgr_lock.acquire()
  77.         self._lock_all()
  78.         for scanner in self._CScanMgr__active_scanners.values():
  79.             if scanner.drive_name == drive_name:
  80.                 result = scanner
  81.                 break
  82.                 continue
  83.         
  84.         for scanner in self._CScanMgr__active_scanners.values():
  85.             if scanner != result:
  86.                 scanner.unlock()
  87.                 continue
  88.         
  89.         self._CScanMgr__mgr_lock.release()
  90.         return result
  91.  
  92.     active_scanners = property((lambda self: self._CScanMgr__active_scanners.copy()))
  93.  
  94. ScanMgr = CScanMgr()
  95.  
  96. def update_quickview():
  97.     app.SetQVCaption(STR_NOT_AVAIL)
  98.     FF = app.GetFocusedFile()
  99.     if FF:
  100.         
  101.         try:
  102.             mft_ref = app.EntryGetMFTRef(FF)
  103.             Volume = app.VolumeForEntry(FF)
  104.             CurrentQVFile = Volume.open_file(mft_ref)
  105.         except Exception:
  106.             Value = None
  107.             traceback.print_exc()
  108.             CurrentQVFile = None
  109.  
  110.         if CurrentQVFile:
  111.             RC = CurrentQVFile.default_data_stream_size >> 4
  112.             if CurrentQVFile.default_data_stream_size & 3:
  113.                 RC += 1
  114.             
  115.             if RC > 4096:
  116.                 RC = 4095
  117.             
  118.             app.SetQVCaption(CurrentQVFile.win32_file_names.keys()[0])
  119.             C = RC * 16
  120.             if C > CurrentQVFile.default_data_stream_size:
  121.                 C = CurrentQVFile.default_data_stream_size
  122.             
  123.             if C > 0:
  124.                 
  125.                 try:
  126.                     data = CurrentQVFile.data_streams[''].read_data(0, C)
  127.                     app.SetQVData(data)
  128.                     app.SetQVRowCount(RC)
  129.                 except Exception:
  130.                     Value = None
  131.                     traceback.print_exc()
  132.                 except:
  133.                     None<EXCEPTION MATCH>Exception
  134.                 
  135.  
  136.             None<EXCEPTION MATCH>Exception
  137.             app.SetQVRowCount(0)
  138.             return None
  139.         
  140.     
  141.  
  142.  
  143. class CNTFSBaseScanner:
  144.     
  145.     def __init__(self, drive_name, device_name = None):
  146.         self._CNTFSBaseScanner__drive_name = drive_name
  147.         self._CNTFSBaseScanner__device_name = device_name
  148.         self._CNTFSBaseScanner__finish_event = threading.Event()
  149.         self._CNTFSBaseScanner__scanner_lock = threading.Lock()
  150.         self._CNTFSBaseScanner__finished = False
  151.         self._CNTFSBaseScanner__locked = False
  152.  
  153.     drive_name = property((lambda self: self._CNTFSBaseScanner__drive_name))
  154.     finish_event = property((lambda self: self._CNTFSBaseScanner__finish_event))
  155.     finished = property((lambda self: self._CNTFSBaseScanner__finished))
  156.     locked = property((lambda self: self._CNTFSBaseScanner__locked))
  157.     
  158.     def lock(self):
  159.         self._CNTFSBaseScanner__scanner_lock.acquire()
  160.         self._CNTFSBaseScanner__locked = True
  161.  
  162.     
  163.     def unlock(self):
  164.         if not self._CNTFSBaseScanner__locked:
  165.             raise AssertionError
  166.         self._CNTFSBaseScanner__locked = False
  167.         self._CNTFSBaseScanner__scanner_lock.release()
  168.  
  169.     
  170.     def run(self):
  171.         ScanMgr.add_scanner(self)
  172.         thread.start_new_thread(self._CNTFSBaseScanner__run, ())
  173.  
  174.     
  175.     def on_drive_open_error(self, ExceptionValue):
  176.         pass
  177.  
  178.     
  179.     def on_volume_open_error(self, ExceptionValue):
  180.         pass
  181.  
  182.     
  183.     def on_open_volume(self, VolumeObject):
  184.         pass
  185.  
  186.     
  187.     def on_open_entry_error(self, mft_ref, ExceptionValue):
  188.         pass
  189.  
  190.     
  191.     def on_open_entry_ok(self, mft_ref, file_object):
  192.         pass
  193.  
  194.     
  195.     def on_scan_finish(self):
  196.         pass
  197.  
  198.     
  199.     def __run(self):
  200.         print 'Base scanner: start scanning device ', self._CNTFSBaseScanner__device_name
  201.         drive_name = self._CNTFSBaseScanner__device_name
  202.         if not drive_name:
  203.             drive_name = self._CNTFSBaseScanner__drive_name
  204.         
  205.         
  206.         try:
  207.             drive = CreateCCachedDisk(CreateCOSDisk(drive_name), 7, 64)
  208.         except Exception:
  209.             Value = None
  210.             print 'Base scanner: drive opening error: ', Value
  211.             traceback.print_exc()
  212.             self.on_drive_open_error(Value)
  213.             ScanMgr.finish_scanner(self)
  214.             return None
  215.  
  216.         
  217.         try:
  218.             volume = CNTFSVolume(drive, 0, drive.sector_count)
  219.             volume.initialize()
  220.         except Exception:
  221.             Value = None
  222.             print 'Base scanner: volume opening error: ', Value
  223.             traceback.print_exc()
  224.             self.on_volume_open_error(Value)
  225.             ScanMgr.finish_scanner(self)
  226.             return None
  227.  
  228.         print 'Base scanner: volume opened successfully'
  229.         self.on_open_volume(volume)
  230.         RC = volume.MFT.mft_record_count
  231.         print 'Base scanner: start scanning for %s $MFT records' % RC
  232.         i = 0x0L
  233.         acq = self._CNTFSBaseScanner__scanner_lock.acquire
  234.         rel = self._CNTFSBaseScanner__scanner_lock.release
  235.         while i < RC:
  236.             acq()
  237.             
  238.             try:
  239.                 file = volume.open_file_if_base(i)
  240.             except Exception:
  241.                 Value = None
  242.                 self.on_open_entry_error(i, Value)
  243.                 i += 1
  244.                 rel()
  245.                 continue
  246.  
  247.             
  248.             try:
  249.                 self.on_open_entry_ok(i, file)
  250.             finally:
  251.                 rel()
  252.  
  253.             i += 1
  254.         print 'Base scanner: scanning process complete'
  255.         self.on_scan_finish()
  256.         self.finish_event.set()
  257.         ScanMgr.finish_scanner(self)
  258.  
  259.  
  260.  
  261. class CNTFSVisualScanner(CNTFSBaseScanner):
  262.     
  263.     def __init__(self, volume_entry):
  264.         self._CNTFSVisualScanner__volume_entry = volume_entry
  265.         drive_name = app.EntryGetName(volume_entry)
  266.         device_name = u'\\\\.\\%s' % drive_name
  267.         self._CNTFSVisualScanner__unk_folder = None
  268.         CNTFSBaseScanner.__init__(self, drive_name, device_name)
  269.  
  270.     unk_folder = property((lambda self: self._CNTFSVisualScanner__unk_folder))
  271.     volume_entry = property((lambda self: self._CNTFSVisualScanner__volume_entry))
  272.     
  273.     def on_open_volume(self, VolumeObject):
  274.         app.EntrySetUserFlag(self._CNTFSVisualScanner__volume_entry, 0, 1)
  275.         app.SetupVolumeObject(self._CNTFSVisualScanner__volume_entry, VolumeObject)
  276.         app.SetScanPercent(self._CNTFSVisualScanner__volume_entry, 0)
  277.         self._CNTFSVisualScanner__unk_folder = app.AddDirectoryEntry(self._CNTFSVisualScanner__volume_entry, -0x7L, 0, u'Lost Files and Folders', 1, 0, 0)
  278.         self._CNTFSVisualScanner__folders = [ None for i in xrange(VolumeObject.MFT.mft_record_count) ]
  279.         self._CNTFSVisualScanner__volume = VolumeObject
  280.         self._CNTFSVisualScanner__tmp_old_oade = self.on_add_directory_entry
  281.         self.on_add_directory_entry = self._CNTFSVisualScanner__on_first_dir_entry
  282.         app.ShowScanDlg(self._CNTFSVisualScanner__volume_entry)
  283.  
  284.     
  285.     def on_drive_open_error(self, ExceptionValue):
  286.         app.ShowMessageModal(STR_DRV_ACCES_ERROR % str(ExceptionValue))
  287.  
  288.     
  289.     def on_volume_open_error(self, ExceptionValue):
  290.         app.ShowMessageModal(STR_CANNOT_OPEN_NTFS_VOLUME)
  291.         print ExceptionValue
  292.         traceback.print_exc()
  293.  
  294.     
  295.     def on_open_entry_error(self, mft_ref, ExceptionValue):
  296.         pass
  297.  
  298.     
  299.     on_add_file_entry = lambda self, entry, entry_to: pass
  300.     
  301.     on_move_entry = lambda self, entry, entry_to: pass
  302.     
  303.     on_add_directory_entry = lambda self, entry, entry_to: pass
  304.     
  305.     def __on_first_dir_entry(self, entry, entry_to):
  306.         app.ExpandEntryEx(self._CNTFSVisualScanner__volume_entry)
  307.         self.on_add_directory_entry = self._CNTFSVisualScanner__tmp_old_oade
  308.         return self._CNTFSVisualScanner__tmp_old_oade(entry, entry_to)
  309.  
  310.     
  311.     def on_open_entry_ok(self, mft_ref, file):
  312.         if mft_ref == 5:
  313.             return None
  314.         
  315.         folders = self._CNTFSVisualScanner__folders
  316.         (creation_time, last_data_change_time, last_access_time, last_mft_change_time, file_attributes) = file.get_standard_info()
  317.         CD = app.NTFSDate2DateTime(creation_time)
  318.         MD = app.NTFSDate2DateTime(last_data_change_time)
  319.         for file_name, file_name_attr in file.win32_file_names.items():
  320.             parent_ref = file_name_attr.get_parent_directory() & 0xFFFFFFFFFFFFL
  321.             if parent_ref >= len(folders):
  322.                 continue
  323.             
  324.             if parent_ref != 5:
  325.                 parent_folder = folders[parent_ref]
  326.             else:
  327.                 parent_folder = self._CNTFSVisualScanner__volume_entry
  328.             if parent_folder is None:
  329.                 parent_folder = app.AddDirectoryEntry(self._CNTFSVisualScanner__unk_folder, parent_ref, 0, u'', 1, 0, 0)
  330.                 folders[parent_ref] = parent_folder
  331.                 self.on_add_directory_entry(parent_folder, self._CNTFSVisualScanner__unk_folder)
  332.             
  333.             if file.is_directory:
  334.                 fld = folders[mft_ref]
  335.                 if fld:
  336.                     app.NotifyChangeEntry(fld, file_name, CD, MD, file.is_deleted)
  337.                     app.MoveEntry(fld, parent_folder)
  338.                     self.on_move_entry(fld, parent_folder)
  339.                 else:
  340.                     folders[mft_ref] = entry = app.AddDirectoryEntry(parent_folder, mft_ref, file.data_stream_count, file_name, file.is_deleted, CD, MD)
  341.                     self.on_add_directory_entry(entry, parent_folder)
  342.             fld
  343.             entry = app.AddFileEntry(parent_folder, mft_ref, file.default_data_stream_size, file.data_stream_count, file_name, file.is_deleted, CD, MD)
  344.             self.on_add_file_entry(entry, parent_folder)
  345.         
  346.         if mft_ref % 256 == 0:
  347.             percent = int(mft_ref * 100.0 / self._CNTFSVisualScanner__volume.MFT.mft_record_count)
  348.             app.SetScanPercent(self._CNTFSVisualScanner__volume_entry, percent)
  349.             print 'SCAN: ', self.drive_name, mft_ref, ' entries processed\r',
  350.         
  351.  
  352.     
  353.     def on_scan_finish(self):
  354.         app.SetScanPercent(self._CNTFSVisualScanner__volume_entry, 100)
  355.         app.HideScanDlg()
  356.  
  357.  
  358.  
  359. def scan_drive():
  360.     print 'Starting scan.'
  361.     CNTFSVisualScanner(app.GetCWD()).run()
  362.  
  363.  
  364. def internal_object_report():
  365.     report = u'\n    <html>\n    <head>\n        <link rel=stylesheet href="file://%s//reports-style.css" type="text/css">\n    </head>\n    <body>\n        <p>Internal object. No properties available.</p>    \n    </body>\n    </html>\n    '
  366.     return report % p_unicode(os.getcwd())
  367.  
  368.  
  369. def make_properties_report(volume, mft_ref):
  370.     if mft_ref < 0:
  371.         return internal_object_report()
  372.     
  373.     general_info_template = STR_GENERAL_INFO_TEMPLATE
  374.     file = CNTFSFile(volume, mft_ref)
  375.     file.open()
  376.     is_deleted = 'No'
  377.     if file.is_deleted:
  378.         is_deleted = 'Yes'
  379.     
  380.     MFTRecords = ''
  381.     j = 1
  382.     for i in file.mft_refs:
  383.         MFTRecords = MFTRecords + '<tr><td>MFT#%i</td><td>%s</td></tr>' % (j, i)
  384.         j += 1
  385.     
  386.     general_info = general_info_template % (p_unicode(os.getcwd()), mft_ref, volume.path_for_mft_ref(mft_ref)[:-1], file.data_stream_count, is_deleted, len(file.mft_records), MFTRecords)
  387.     return general_info
  388.  
  389. SearchActive = False
  390. search_lock = threading.Lock()
  391.  
  392. class CSearchScanMixin:
  393.     
  394.     def __init__(self, scanner, validation_cb, finish_evt, recurse_search_cb):
  395.         self._CSearchScanMixin__scanner = scanner
  396.         self._CSearchScanMixin__validation_cb = validation_cb
  397.         self._CSearchScanMixin__recurse_search_cb = recurse_search_cb
  398.         self._CSearchScanMixin__finish_evt = finish_evt
  399.  
  400.     scanner = property((lambda self: self._CSearchScanMixin__scanner))
  401.     
  402.     def __check_activity(self):
  403.         if not SearchActive:
  404.             self.detach_mixin()
  405.             self._CSearchScanMixin__finish_evt.set()
  406.             return False
  407.         
  408.         return True
  409.  
  410.     
  411.     def __on_add_file_entry(self, entry, entry_to):
  412.         self._old_on_add_file_entry(entry, entry_to)
  413.         if self._CSearchScanMixin__check_activity():
  414.             if not app.EntryHasUnkEntryParent(entry):
  415.                 self._CSearchScanMixin__validation_cb(entry)
  416.             
  417.         
  418.  
  419.     
  420.     def __on_drive_open_error(self, ExceptionValue):
  421.         self._CSearchScanMixin__finish_evt.set()
  422.  
  423.     
  424.     def __on_volume_open_error(self, ExceptionValue):
  425.         self._CSearchScanMixin__finish_evt.set()
  426.  
  427.     
  428.     def __on_add_directory_entry(self, entry, entry_to):
  429.         self._old_on_add_directory_entry(entry, entry_to)
  430.         if self._CSearchScanMixin__check_activity():
  431.             if not app.EntryHasUnkEntryParent(entry):
  432.                 self._CSearchScanMixin__validation_cb(entry)
  433.             
  434.         
  435.  
  436.     
  437.     def __on_move_entry(self, entry, entry_to):
  438.         self._old_on_move_entry(entry, entry_to)
  439.         if self._CSearchScanMixin__check_activity():
  440.             if not app.EntryHasUnkEntryParent(entry):
  441.                 self._CSearchScanMixin__recurse_search_cb(entry)
  442.             
  443.         
  444.  
  445.     
  446.     def __on_scan_finish(self):
  447.         self._old_on_scan_finish()
  448.         self._CSearchScanMixin__finish_evt.set()
  449.  
  450.     
  451.     def attach_mixin(self, scanner, *args):
  452.         mixin = self(scanner, *args)
  453.         mixin._old_on_add_file_entry = scanner.on_add_file_entry
  454.         mixin._old_on_add_directory_entry = scanner.on_add_directory_entry
  455.         mixin._old_on_move_entry = scanner.on_move_entry
  456.         mixin._old_on_scan_finish = scanner.on_scan_finish
  457.         mixin._old_on_drive_open_error = scanner.on_drive_open_error
  458.         mixin._old_on_volume_open_error = scanner.on_volume_open_error
  459.         scanner.on_add_file_entry = mixin._CSearchScanMixin__on_add_file_entry
  460.         scanner.on_add_directory_entry = mixin._CSearchScanMixin__on_add_directory_entry
  461.         scanner.on_move_entry = mixin._CSearchScanMixin__on_move_entry
  462.         scanner.on_scan_finish = mixin._CSearchScanMixin__on_scan_finish
  463.         scanner.on_drive_open_error = mixin._CSearchScanMixin__on_drive_open_error
  464.         scanner.on_volume_open_error = mixin._CSearchScanMixin__on_volume_open_error
  465.         return mixin
  466.  
  467.     attach_mixin = classmethod(attach_mixin)
  468.     
  469.     def detach_mixin(self):
  470.         scanner = self.scanner
  471.         scanner.on_add_file_entry = self._old_on_add_file_entry
  472.         scanner.on_add_directory_entry = self._old_on_add_directory_entry
  473.         scanner.on_move_entry = self._old_on_move_entry
  474.         scanner.on_drive_open_error = self._old_on_drive_open_error
  475.         scanner.on_volume_open_error = self._old_on_volume_open_error
  476.  
  477.  
  478.  
  479. def search_files():
  480.     FoundResults = 0x0L
  481.     
  482.     def do_search():
  483.         global FoundResults
  484.         app.InitSearch()
  485.         FoundResults = 0x0L
  486.         search_params = app.GetSearchParams()
  487.         look_in = search_params['look_in']
  488.         if type(look_in) != type(1):
  489.             _do_search(look_in)
  490.         else:
  491.             root = app.GetRootEntry()
  492.             entry = app.EntryGetFirstChild(root)
  493.             while entry:
  494.                 if app.EntryIsDrive(entry):
  495.                     _do_search(entry)
  496.                 
  497.                 entry = app.EntryGetNext(entry)
  498.         app.DoneSearch()
  499.         app.ShowMessageModal(STR_SEARCH_COMPLETE % FoundResults)
  500.  
  501.     
  502.     def _do_search(search_start_entry):
  503.         global SearchActive, FoundResults
  504.         print 'Search start...'
  505.         SearchActive = True
  506.         search_params = app.GetSearchParams()
  507.         masks = map((lambda x: x.strip()), search_params['masks'].split(','))
  508.         case_sensitive = search_params['case_sensitive']
  509.         search_folders = search_params['search_folders']
  510.         search_files = search_params['search_files']
  511.         search_deleted = search_params['deleted_entries']
  512.         search_non_deleted = search_params['non_deleted_entries']
  513.         use_modify_filter = search_params['use_modify_filter']
  514.         modify_from = None
  515.         modify_to = None
  516.         if use_modify_filter:
  517.             modify_from = search_params['modify_from']
  518.             modify_to = search_params['modify_to']
  519.         
  520.         use_create_filter = search_params['use_create_filter']
  521.         created_from = None
  522.         created_to = None
  523.         if use_create_filter:
  524.             created_from = search_params['created_from']
  525.             created_to = search_params['created_to']
  526.         
  527.         if not case_sensitive:
  528.             masks = map((lambda mask: mask.upper()), masks)
  529.         
  530.         size_from = search_params.get('size_from', None)
  531.         if size_from:
  532.             (a, b) = tuple(filter((lambda x: x != ''), size_from.split(' ')))
  533.             size_from = long(a)
  534.             if b == 'KB':
  535.                 size_from *= 0x400L
  536.             elif b == 'MB':
  537.                 size_from *= 0x400L * 0x400L
  538.             elif b == 'GB':
  539.                 size_from *= 0x400L * 0x400L * 0x400L
  540.             
  541.         
  542.         size_to = search_params.get('size_to', None)
  543.         if size_to:
  544.             (a, b) = tuple(filter((lambda x: x != ''), size_to.split(' ')))
  545.             size_to = long(a)
  546.             if b == 'KB':
  547.                 size_to *= 0x400L
  548.             elif b == 'MB':
  549.                 size_to *= 0x400L * 0x400L
  550.             elif b == 'GB':
  551.                 size_to *= 0x400L * 0x400L * 0x400L
  552.             
  553.         
  554.         _entries = { }
  555.         
  556.         def _validate_entry(entry):
  557.             name = app.EntryGetName(entry)
  558.             if not case_sensitive:
  559.                 name = name.upper()
  560.             
  561.             for mask in masks:
  562.                 if mask == '*.*':
  563.                     mask = '*'
  564.                 
  565.                 if not app.FileNameMatches(name, unicode(mask)):
  566.                     continue
  567.                 
  568.                 if not (search_files or app.EntryIsFile(entry)) and search_folders and app.EntryIsDirectory(entry):
  569.                     continue
  570.                 
  571.                 if not (search_deleted or app.EntryIsDeleted(entry)) and search_non_deleted and not app.EntryIsDeleted(entry):
  572.                     continue
  573.                 
  574.                 if use_modify_filter:
  575.                     MD = app.EntryGetModifyDate(entry)
  576.                     if not MD >= modify_from and MD < modify_to + 1:
  577.                         continue
  578.                     
  579.                 
  580.                 if use_create_filter:
  581.                     CD = app.EntryGetCreateDate(entry)
  582.                     if not CD >= created_from and CD < created_to + 1:
  583.                         continue
  584.                     
  585.                 
  586.                 if size_from is not None and app.EntryIsFile(entry):
  587.                     if not app.EntryGetDataSize(entry) >= size_from:
  588.                         continue
  589.                     
  590.                 
  591.                 if size_to is not None and app.EntryIsFile(entry):
  592.                     if not app.EntryGetDataSize(entry) <= size_to:
  593.                         continue
  594.                     
  595.                 
  596.                 mft_ref = app.EntryGetMFTRef(entry)
  597.                 if not _entries.has_key(mft_ref):
  598.                     app.AddSearchResult(entry)
  599.                     _entries[mft_ref] = entry
  600.                 
  601.             
  602.  
  603.         
  604.         def _caption_thread(evt):
  605.             while True:
  606.                 for i in xrange(6):
  607.                     evt.wait(0.5)
  608.                     if evt.isSet():
  609.                         return None
  610.                     
  611.                     app.SetSearchCaption(u'Searching ' + u'.' * i)
  612.                 
  613.  
  614.         skip_unk_entry = False
  615.         
  616.         def _search_from(entry):
  617.             while entry and SearchActive:
  618.                 _validate_entry(entry)
  619.                 if app.EntryIsContainer(entry):
  620.                     if skip_unk_entry and app.EntryIsDirectory(entry) and app.EntryGetMFTRef(entry) == -7:
  621.                         entry = app.EntryGetNext(entry)
  622.                         continue
  623.                     
  624.                     _search_from(app.EntryGetFirstChild(entry))
  625.                 
  626.                 entry = app.EntryGetNext(entry)
  627.  
  628.         
  629.         def _recurse_search(entry):
  630.             if entry:
  631.                 _validate_entry(entry)
  632.                 _search_from(app.EntryGetFirstChild(entry))
  633.             
  634.  
  635.         search_finished = threading.Event()
  636.         
  637.         def __on_search_init_error(ExceptionValue):
  638.             search_finished.set()
  639.             app.ShowMessageModal(STR_NON_NTFS_DRIVE % (app.EntryGetName(search_start_entry),))
  640.  
  641.         entry_name = app.EntryGetName(search_start_entry)
  642.         search_lock.acquire()
  643.         if app.EntryIsDriveNotScanned(search_start_entry):
  644.             scanner = CNTFSVisualScanner(search_start_entry)
  645.             scanner.on_drive_open_error = __on_search_init_error
  646.             scanner.on_volume_open_error = __on_search_init_error
  647.             scanner.run()
  648.         
  649.         search_lock.release()
  650.         scanner = ScanMgr.find_scanner_for_drive(entry_name)
  651.         thread.start_new_thread(_caption_thread, (search_finished,))
  652.         if scanner is None:
  653.             _recurse_search(search_start_entry)
  654.             search_finished.set()
  655.         else:
  656.             skip_unk_entry = True
  657.             _recurse_search(search_start_entry)
  658.             skip_unk_entry = False
  659.             CSearchScanMixin.attach_mixin(scanner, _validate_entry, search_finished, _search_from)
  660.             scanner.unlock()
  661.             search_finished.wait()
  662.             _recurse_search(scanner.unk_folder)
  663.         print '\n\nFOUND: ', app.GetSearchResultCount()
  664.         FoundResults += app.GetSearchResultCount()
  665.  
  666.     thread.start_new_thread(do_search, ())
  667.  
  668.  
  669. def cancel_search():
  670.     global SearchActive
  671.     SearchActive = False
  672.  
  673.  
  674. def get_checked_entries():
  675.     result = []
  676.     
  677.     def recurse_process(entry):
  678.         if app.EntryIsChecked(entry):
  679.             result.append(entry)
  680.             if app.EntryIsContainer(entry):
  681.                 entry = app.EntryGetFirstChild(entry)
  682.                 while entry:
  683.                     recurse_process(entry)
  684.                     entry = app.EntryGetNext(entry)
  685.             
  686.         
  687.  
  688.     recurse_process(app.GetRootEntry())
  689.     return result
  690.  
  691.  
  692. def local_path_for_entry(entry):
  693.     if app.EntryIsDrive(entry):
  694.         return app.EntryGetName(entry)[0]
  695.     
  696.     parent = app.EntryGetParent(entry)
  697.     if parent:
  698.         return local_path_for_entry(parent) + u'\\' + app.EntryGetName(entry)
  699.     else:
  700.         return u''
  701.  
  702.  
  703. def real_path_for_entry(entry):
  704.     parent = app.EntryGetParent(entry)
  705.     if parent:
  706.         return real_path_for_entry(parent) + u'\\' + app.EntryGetName(entry)
  707.     else:
  708.         return u''
  709.  
  710.  
  711. def get_entry_parents(entry):
  712.     R = []
  713.     p = app.EntryGetParent(entry)
  714.     while p:
  715.         R.append(p)
  716.         p = app.EntryGetParent(p)
  717.     return R
  718.  
  719.  
  720. def get_minimal_common_parent_id(file_entries):
  721.     c = { }
  722.     d = { }
  723.     for e in file_entries:
  724.         parents = get_entry_parents(e)
  725.         dpt = len(parents)
  726.         for parent in parents:
  727.             pid = app.EntryGetID(parent)
  728.             d[pid] = dpt
  729.             dpt -= 1
  730.             if c.has_key(pid):
  731.                 c[pid] += 1
  732.                 continue
  733.             c[pid] = 1
  734.         
  735.     
  736.     items = [ (b, d[a], a) for a, b in c.items() ]
  737.     items.sort()
  738.     mpid = -0x1L
  739.     return mpid
  740.  
  741.  
  742. def path_upto_parent(entry, parent_id):
  743.     parent = app.EntryGetParent(entry)
  744.     if parent and app.EntryGetID(parent) != parent_id:
  745.         pp = path_upto_parent(parent, parent_id)
  746.         if pp:
  747.             return pp + u'\\' + app.EntryGetName(entry)
  748.         else:
  749.             return app.EntryGetName(entry)
  750.     elif parent:
  751.         if not app.EntryIsDrive(entry):
  752.             return app.EntryGetName(entry)
  753.         else:
  754.             return app.EntryGetName(entry)[0]
  755.     else:
  756.         return u''
  757.  
  758. RecoveryRunning = False
  759. RecoverySkip = False
  760. rmtMessage = 1
  761. rmtError = 2
  762. rmtWarning = 3
  763. rmtSuccess = 4
  764.  
  765. def start_recovery():
  766.     
  767.     class RecoveryContext:
  768.         
  769.         def __init__(self):
  770.             self.total_files = 0
  771.             self.total_size = 0x0L
  772.             self.processed_files = 0
  773.             self.processed_size = 0x0L
  774.             self.current_file_name = u''
  775.             self.current_file_progress = 0
  776.  
  777.  
  778.     
  779.     def emit(cls, s):
  780.         app.EmitRecoveryMessage(cls, s)
  781.  
  782.     
  783.     def generate_autoname(path):
  784.         for i in xrange(1000):
  785.             fname = path + u'#' + str(i)
  786.             if not os.path.exists(fname):
  787.                 return fname
  788.                 continue
  789.         
  790.         raise Exception('Unable to generate file name for ' + path)
  791.  
  792.     
  793.     def uprecurse_uncheck(entry):
  794.         app.UnmarkEntry(entry)
  795.         parent = app.EntryGetParent(entry)
  796.         if parent and not app.EntryHasMarkedChildren(parent):
  797.             app.UnmarkEntry(parent)
  798.             uprecurse_uncheck(parent)
  799.         
  800.  
  801.     
  802.     def copy_file(entry, target_path, context, rparams):
  803.         global RecoverySkip
  804.         recover_all_data_strems = rparams['recover_all_data_strems']
  805.         delete_unsuccessful = rparams['delete_unsuccessful']
  806.         naming = rparams['naming']
  807.         unchecking = rparams['unchecking']
  808.         context.current_file_progress = 0
  809.         RecoverySkip = False
  810.         BULK = 256 * 1024
  811.         processed_size = 0x0L
  812.         total_size = 0x0L
  813.         file_name = None
  814.         has_errors = False
  815.         f = None
  816.         
  817.         try:
  818.             volume = app.VolumeForEntry(entry)
  819.             mft_ref = app.EntryGetMFTRef(entry)
  820.             if volume and mft_ref >= 0:
  821.                 file = volume.open_file(mft_ref)
  822.                 if len(file.data_streams) > 1:
  823.                     emit(rmtMessage, STR_KNOWN_DATA_STREAMS + unicode(str(file.data_streams.keys())))
  824.                 
  825.                 total_size = reduce((lambda x, y: y.size + x), file.data_streams.values(), 0x0L)
  826.                 for data_stream_name, data_stream in file.data_streams.items():
  827.                     is_alter_stream = len(data_stream_name) > 0
  828.                     if is_alter_stream and not recover_all_data_strems:
  829.                         continue
  830.                     
  831.                     if data_stream_name:
  832.                         context.current_file_name = app.EntryGetName(entry) + u' stream: ' + data_stream_name
  833.                     else:
  834.                         context.current_file_name = app.EntryGetName(entry)
  835.                     file_name = target_path
  836.                     if data_stream_name:
  837.                         file_name += u'_' + data_stream_name
  838.                     
  839.                     if os.path.exists(file_name):
  840.                         if naming == 0:
  841.                             file_name = generate_autoname(file_name)
  842.                         elif naming == 1:
  843.                             file_name = app.SaveDlgQuery(file_name)
  844.                             if not file_name:
  845.                                 raise Exception(STR_USER_SKIPPED)
  846.                             
  847.                         elif naming == 2:
  848.                             continue
  849.                         
  850.                     
  851.                     f = open(file_name, 'wb')
  852.                     pos = 0x0L
  853.                     count = data_stream.size
  854.                     while count > 0:
  855.                         if not RecoveryRunning:
  856.                             raise Exception(STR_USER_CANCELLED)
  857.                         
  858.                         if RecoverySkip:
  859.                             if not is_alter_stream:
  860.                                 context.processed_size += count
  861.                             
  862.                             raise Exception(STR_USER_SKIPPED)
  863.                         
  864.                         C = BULK
  865.                         if C > count:
  866.                             C = count
  867.                         
  868.                         
  869.                         try:
  870.                             data = data_stream.read_data(pos, C)
  871.                             pos += C
  872.                             count -= C
  873.                             processed_size += C
  874.                             context.current_file_progress = int(processed_size * 100.0 / total_size)
  875.                             f.write(data)
  876.                         finally:
  877.                             pass
  878.  
  879.                     f.close()
  880.                     f = None
  881.                     if is_alter_stream:
  882.                         emit(rmtSuccess, u'Recovered ok - ' + app.EntryGetPath(entry) + u' stream ' + data_stream_name)
  883.                         continue
  884.                     emit(rmtSuccess, u'Recovered ok - ' + app.EntryGetPath(entry))
  885.                 
  886.             else:
  887.                 raise Exception(STR_CANNOT_OPEN_FILE % (mft_ref, str(volume)))
  888.         except Exception:
  889.             Value = None
  890.             has_errors = True
  891.             emit(rmtError, STR_ERROR_ON % (target_path, str(Value)))
  892.             if f:
  893.                 f.close()
  894.             
  895.             if file_name and delete_unsuccessful:
  896.                 
  897.                 try:
  898.                     os.remove(file_name)
  899.                 except Exception:
  900.                     Value = None
  901.                 except:
  902.                     None<EXCEPTION MATCH>Exception
  903.                 
  904.  
  905.             None<EXCEPTION MATCH>Exception
  906.  
  907.         context.processed_files += 1
  908.         if unchecking == 0 or not has_errors or unchecking == 1:
  909.             uprecurse_uncheck(entry)
  910.         
  911.  
  912.     
  913.     def report_thread(context):
  914.         while RecoveryRunning:
  915.             if context.total_size:
  916.                 total_progress = int(context.processed_size * 100.0 / context.total_size)
  917.                 if total_progress > 100:
  918.                     total_progress = 100
  919.                 
  920.                 app.NotifyRecoveryProgress(context.current_file_name, context.current_file_progress, total_progress, context.total_files, context.processed_files, context.total_files - context.processed_files, u'unknown', u'unknown', u'unknown')
  921.             
  922.             time.sleep(0.10000000000000001)
  923.         app.NotifyRecoveryProgress(context.current_file_name, context.current_file_progress, 100, context.total_files, context.processed_files, context.total_files - context.processed_files, u'unknown', u'unknown', u'unknown')
  924.         app.RecoveryPanelDone()
  925.  
  926.     
  927.     def recovery():
  928.         global RecoveryRunning, total_files, RecoveryRunning
  929.         RecoveryRunning = True
  930.         
  931.         try:
  932.             app.RecoveryPanelInit()
  933.             rparams = app.GetRecoveryParams()
  934.             recover_folder_structure = rparams['recover_folder_structure']
  935.             dst_folder = rparams['recovery_folder']
  936.             if not os.path.exists(dst_folder):
  937.                 
  938.                 try:
  939.                     os.makedirs(dst_folder)
  940.                 S = STR_CANNOT_CREATE_FOLDER + dst_folder
  941.                 app.ShowMessageModal(S)
  942.                 raise Exception(S)
  943.  
  944.             
  945.             c = dst_folder[-1]
  946.             if c != '\\' and c != '/':
  947.                 dst_folder += '\\'
  948.             
  949.             _drv = os.path.abspath(dst_folder)[:2]
  950.             emit(rmtMessage, STR_START_RECOVERY_TO + dst_folder)
  951.             emit(rmtMessage, STR_GEN_FILE_LIST)
  952.             entries = get_checked_entries()
  953.             files = filter((lambda entry: app.EntryIsFile(entry)), entries)
  954.             mcpid = get_minimal_common_parent_id(files)
  955.             total_files = len(files)
  956.             total_size = reduce((lambda x, y: app.EntryGetDataSize(y) + x), files, 0x0L)
  957.             emit(rmtMessage, STR_FILE_LIST_GENERATED % (len(entries), total_files, total_size))
  958.             context = RecoveryContext()
  959.             context.total_files = total_files
  960.             context.total_size = total_size
  961.             thread.start_new_thread(report_thread, (context,))
  962.             for fe in entries:
  963.                 if app.EntryGetPath(fe)[:2].upper() == _drv.upper():
  964.                     if app.ShowYesNoDlg(u'It is not safe to recover some files into the folder you specified, recovered files can be corrupted. Do you want to proceed anyway?') == 7:
  965.                         raise Exception(STR_USER_CANCELLED)
  966.                     else:
  967.                         break
  968.                 app.ShowYesNoDlg(u'It is not safe to recover some files into the folder you specified, recovered files can be corrupted. Do you want to proceed anyway?') == 7
  969.             
  970.             if len(entries) > 0:
  971.                 del entries[0]
  972.                 for entry in files:
  973.                     if not RecoveryRunning:
  974.                         break
  975.                     
  976.                     full_path = None
  977.                     if recover_folder_structure:
  978.                         full_path = dst_folder + path_upto_parent(entry, mcpid)
  979.                     else:
  980.                         full_path = dst_folder + app.EntryGetName(entry)
  981.                     print 'UPTO PATH: ', path_upto_parent(entry, mcpid)
  982.                     dirs = u'\\'.join(full_path.split(u'\\')[:-1])
  983.                     if not os.path.exists(dirs):
  984.                         print 'Create dirs: ', dirs
  985.                         os.makedirs(dirs)
  986.                     
  987.                     copy_file(entry, full_path, context, rparams)
  988.                 
  989.         finally:
  990.             RecoveryRunning = False
  991.  
  992.  
  993.     thread.start_new_thread(recovery, ())
  994.  
  995.  
  996. def recovery_stop():
  997.     global RecoveryRunning
  998.     RecoveryRunning = False
  999.  
  1000.  
  1001. def recovery_pause():
  1002.     app.ShowMessageModal(STR_RECOVERY_PAUSED)
  1003.  
  1004.  
  1005. def recovery_skip_current_file():
  1006.     global RecoverySkip
  1007.     RecoverySkip = True
  1008.  
  1009.  
  1010. def execute_script(script_path):
  1011.     
  1012.     def _doexec():
  1013.         execfile(script_path)
  1014.  
  1015.     thread.start_new_thread(_doexec, ())
  1016.  
  1017. progress_dlg_cancel = False
  1018.  
  1019. def save_as():
  1020.     
  1021.     def _do_save_as():
  1022.         global progress_dlg_cancel
  1023.         progress_dlg_cancel = False
  1024.         ff = app.GetFocusedFile()
  1025.         if ff:
  1026.             file_name = app.SaveDlgQuery(app.EntryGetName(ff))
  1027.             if not file_name:
  1028.                 return None
  1029.             
  1030.             file_name = os.path.abspath(file_name)
  1031.             if file_name[:2].upper() == app.EntryGetPath(ff)[:2].upper():
  1032.                 if app.ShowYesNoDlg(u'It is not safe to recover the file to destination you specified, recovered files can be corrupted. Do you want to proceed anyway?') == 7:
  1033.                     return None
  1034.                 
  1035.             
  1036.             if file_name:
  1037.                 BULK = 256 * 1024
  1038.                 app.ShowProgressDlg(u'Copy...', u'Copy file ' + app.EntryGetName(ff) + u' to ' + file_name)
  1039.                 entry = ff
  1040.                 target_path = file_name
  1041.                 
  1042.                 try:
  1043.                     volume = app.VolumeForEntry(entry)
  1044.                     mft_ref = app.EntryGetMFTRef(entry)
  1045.                     if volume and mft_ref >= 0:
  1046.                         file = volume.open_file(mft_ref)
  1047.                         total_size = reduce((lambda x, y: y.size + x), file.data_streams.values(), 0x0L)
  1048.                         processed_size = 0x0L
  1049.                         for data_stream_name, data_stream in file.data_streams.items():
  1050.                             is_alter_stream = len(data_stream_name) > 0
  1051.                             file_name = target_path
  1052.                             if data_stream_name:
  1053.                                 file_name += u'_' + data_stream_name
  1054.                             
  1055.                             f = open(file_name, 'wb')
  1056.                             pos = 0x0L
  1057.                             count = data_stream.size
  1058.                             while count > 0:
  1059.                                 if progress_dlg_cancel:
  1060.                                     raise Exception(STR_USER_CANCELLED)
  1061.                                 
  1062.                                 C = BULK
  1063.                                 if C > count:
  1064.                                     C = count
  1065.                                 
  1066.                                 data = data_stream.read_data(pos, C)
  1067.                                 pos += C
  1068.                                 count -= C
  1069.                                 processed_size += C
  1070.                                 f.write(data)
  1071.                                 perc = int(pos * 100.0 / data_stream.size)
  1072.                                 app.NotifyProgressDlg(perc)
  1073.                             f.close()
  1074.                         
  1075.                 except:
  1076.                     traceback.print_exc()
  1077.  
  1078.                 app.HideProgressDlg()
  1079.             
  1080.         
  1081.  
  1082.     thread.start_new_thread(_do_save_as, ())
  1083.  
  1084.  
  1085. def on_progress_dlg_cancel():
  1086.     global progress_dlg_cancel
  1087.     progress_dlg_cancel = True
  1088.  
  1089.  
  1090. def on_application_close():
  1091.     global RecoveryRunning, SearchActive, ScannerActive
  1092.     RecoveryRunning = False
  1093.     SearchActive = False
  1094.     ScannerActive = False
  1095.  
  1096.